# -*- coding: utf-8 -*-
#!/usr/bin/env python3

__version__ = "0.1"
__all__ = ["SimpleHTTPRequestHandler"]
 
import os
import posixpath
import webbrowser
import http.server
import urllib.request, urllib.parse, urllib.error
import cgi
import shutil
import mimetypes
import re
from io import BytesIO
 
 
class SimpleHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
    server_version = "SimpleHTTPWithUpload/" + __version__
    def do_GET(self):"
        f = self.send_head()
        if f:
            self.copyfile(f, self.wfile)
            f.close()
 
    def do_HEAD(self):
        f = self.send_head()
        if f:
            f.close()
 
    def do_POST(self):
        r, info = self.deal_post_data()
        print((r, info, "by: ", self.client_address))
        f = BytesIO()
        f.write(b'<!DOCTYPE html>')
        f.write(b"<html>\n<meta charset=\"utf-8\">\n<title>\xe4\xb8\x8a\xe4\xbc\xa0\xe5\xae\x8c\xe6\x88\x90</title>\n")
        f.write(b"<body style='background:#00c3ff;>\n<h2>\xe4\xb8\x8a\xe4\xbc\xa0\xe5\xae\x8c\xe6\x88\x90</h2>\n")
        f.write(b"<hr>\n")
        if r:
            f.write(b"<strong>\xe4\xb8\x8a\xe4\xbc\xa0\xe6\x88\x90\xe5\x8a\x9f:</strong>")
        else:
            f.write(b"<strong>\xe4\xb8\x8a\xe4\xbc\xa0\xe5\xa4\xb1\xe8\xb4\xa5:</strong>")
        f.write(info.encode())
        f.write(("<br><a href=\"%s\" style=\"text-decoration:none;color:white;\">返回</a>" % self.headers['referer']).encode())
        f.write(b"<hr></body>\n</html>\n")
        length = f.tell()
        f.seek(0)
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.send_header("Content-Length", str(length))
        self.end_headers()
        if f:
            self.copyfile(f, self.wfile)
            f.close()
        
    def deal_post_data(self):
        content_type = self.headers['content-type']
        if not content_type:
            return (False, "Content-Type header doesn't contain boundary")
        boundary = content_type.split("=")[1].encode()
        remainbytes = int(self.headers['content-length'])
        line = self.rfile.readline()
        remainbytes -= len(line)
        if not boundary in line:
            return (False, "Content NOT begin with boundary")
        line = self.rfile.readline()
        remainbytes -= len(line)
        fn = re.findall(r'Content-Disposition.*name="file"; filename="(.*)"', line.decode())
        if not fn:
            return (False, "Can't find out file name...")
        path = self.translate_path(self.path)
        fn = os.path.join(path, fn[0])
        line = self.rfile.readline()
        remainbytes -= len(line)
        line = self.rfile.readline()
        remainbytes -= len(line)
        try:
            out = open(fn, 'wb')
        except IOError:
            return (False, "Can't create file to write, do you have permission to write?")
                
        preline = self.rfile.readline()
        remainbytes -= len(preline)
        while remainbytes > 0:
            line = self.rfile.readline()
            remainbytes -= len(line)
            if boundary in line:
                preline = preline[0:-1]
                if preline.endswith(b'\r'):
                    preline = preline[0:-1]
                out.write(preline)
                out.close()
                return (True, "File '%s' upload success!" % fn)
            else:
                out.write(preline)
                preline = line
        return (False, "Unexpect Ends of data.")
 
    def send_head(self):
        path = self.translate_path(self.path)
        f = None
        if os.path.isdir(path):
            if not self.path.endswith('/'):
                self.send_response(301)
                self.send_header("Location", self.path + "/")
                self.end_headers()
                return None
            for index in "index.html", "index.htm":
                index = os.path.join(path, index)
                if os.path.exists(index):
                    path = index
                    break
            else:
                return self.list_directory(path)
        ctype = self.guess_type(path)
        try:
            f = open(path, 'rb')
        except IOError:
            self.send_error(404, "File not found")
            return None
        self.send_response(200)
        self.send_header("Content-type", ctype)
        fs = os.fstat(f.fileno())
        self.send_header("Content-Length", str(fs[6]))
        self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
        self.end_headers()
        return f
 
    def list_directory(self, path):
        try:
            list = os.listdir(path)
        except os.error:
            self.send_error(404, "No permission to list directory")
            return None
        list.sort(key=lambda a: a.lower())
        f = BytesIO()
        displaypath = cgi.escape(urllib.parse.unquote(self.path))
        f.write(b'<!DOCTYPE html>')
        f.write(("<html>\n<meta charset=\"UTF-8\">\n<title>资源管理器  %s</title>\n</head>\n" % displaypath).encode())
        f.write(("<body style='background:#00c3ff;'>\n<h2>资源管理器  %s</h2>\n" % displaypath).encode())
        f.write(b"<hr>\n<h4>\xe4\xb8\x8a\xe4\xbc\xa0\xe6\x96\x87\xe4\xbb\xb6</h4>\n")
        f.write(b"<form ENCTYPE=\"multipart/form-data\" method=\"post\">")
        f.write(b"<button style='width: 270px;height: 40px;border-width: 0px;border-radius: 3px;background: #1E90FF;cursor: pointer;outline: none;color: white;font-size: 17px;'>\xe9\x80\x89\xe6\x8b\xa9\xe6\x96\x87\xe4\xbb\xb6<input name=\"file\" type=\"file\"/ style=\"opacity:0;width:270px;height:40px;position:absolute;top: 136px;left: 8px;\"></button><br><br>")
        f.write(b"<input type=\"submit\" value=\"\xe4\xb8\x8a\xe4\xbc\xa0\"/ style='width: 270px;height: 40px;border-width: 0px;border-radius: 3px;background: #1E90FF;cursor: pointer;outline: none;color: white;font-size: 17px;'></form>\n")
        f.write(b"<hr>\n<a href=\"../\" style=\"text-decoration:none;color:white;\">\xe2\x86\x91  \xe4\xb8\x8a\xe4\xb8\x80\xe7\xba\xa7</a>\n<ul style=\"list-style-type: \'\';\">\n")
        for name in list:
            fullname = os.path.join(path, name)
            displayname = linkname = name
            if os.path.isdir(fullname):
                displayname = name + "/"
                linkname = name + "/"
            if os.path.islink(fullname):
                displayname = name + "@"
            f.write(('<li><a href="./%s" style="text-decoration:none;color:white;">📄  %s</a>\n'
                    % (urllib.parse.quote(linkname), cgi.escape(displayname))).encode())
        f.write(b"</ul>\n<hr>\n</body>\n</html>\n")
        length = f.tell()
        f.seek(0)
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.send_header("Content-Length", str(length))
        self.end_headers()
        return f
 
    def translate_path(self, path):
        path = path.split('?',1)[0]
        path = path.split('#',1)[0]
        path = posixpath.normpath(urllib.parse.unquote(path))
        words = path.split('/')
        words = [_f for _f in words if _f]
        path = os.getcwd()
        for word in words:
            drive, word = os.path.splitdrive(word)
            head, word = os.path.split(word)
            if word in (os.curdir, os.pardir): continue
            path = os.path.join(path, word)
        return path
 
    def copyfile(self, source, outputfile):
        shutil.copyfileobj(source, outputfile)
    def guess_type(self, path):
        base, ext = posixpath.splitext(path)
        if ext in self.extensions_map:
            return self.extensions_map[ext]
        ext = ext.lower()
        if ext in self.extensions_map:
            return self.extensions_map[ext]
        else:
            return self.extensions_map['']
 
    if not mimetypes.inited:
        mimetypes.init()
    extensions_map = mimetypes.types_map.copy()
    extensions_map.update({
        '': 'application/octet-stream',
        '.py': 'text/plain',
        '.c': 'text/plain',
        '.h': 'text/plain',
        })
def test(HandlerClass = SimpleHTTPRequestHandler,
        ServerClass = http.server.HTTPServer):
    http.server.test(HandlerClass, ServerClass)
if __name__ == '__main__':
    webbrowser.open("http://localhost:8000/")
    test()   
